#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
// The Function that lets me not use cls, clearscreen
void pass()
    {
        string w;
      cout << "Please Enter Any Key then Enter to Continue" << endl;
            getline(cin, w);
            getline(cin, w);
            cout << string(50, '\n');            
        }
//Function List

double sec(double x)
{
    return (1.0/cos(x));
}
double F0(double x) //Function for Equation 1
{
    return (sin(x)- exp(-0.1*x));
};
double dF0(double x)
{
    return (0.1*exp(-0.1*x) + cos(x));
}
double F1(double x)
{
    return (cos(2*x) + pow(x,3));
}
double dF1(double x)
{
    return (3*pow(x,2)-2*sin(2*x));
}
double F2(double x)
{
    return (sin(3*x) + cos (3*x) + pow (x,4));
}
double dF2(double x)
{
    return (4*pow(x,3) - 3*sin(3*x) + 3*cos(3*x));
}
double F3(double x)
{
    return (pow(sin(3*x),3) + pow(sin(2*x),2) + sin(1*x));
}
double dF3(double x)
{
    return (2*sin(4*x) + cos(x) + 9*pow(sin(3*x),2)*cos(3*x));
}
double F4(double x)
{
    return(cos(x) + sin(x) + tan(x));
}
double dF4(double x)
{
    return (-sin(x) + cos(x) + pow(sec(x),2));
}

void Funchoice() // Function for choosing which function to select to be used in switch statement
{
    cout << "Select a Function:" << endl;
    cout << " [1] sin(x)-e^(-0.1x)" << endl;
    cout << " [2] cos(2x) + x^3 " << endl;
    cout << " [3] cos(3x) + sin(3x) + x^4 " << endl;
    cout << " [4] (sin(3x))^3 + (sin(2x))^2 + sin(x)" << endl;
    cout << " [5] cos(x) + sin(x) + tan(x)  " << endl;
};

void MethodChoice() // Function for choosing which function to select to be used in switch statement
{
    cout << "Select a Root-Finding Method:" << endl;
    cout << " [1] Newton-Raphson Method" << endl;
    cout << " [2] Secant Method" << endl;
    cout << " [3] Bisection Method " << endl;
    cout << " [4] False Position Method" << endl;
    cout << " [5] All Above Stated Methods" << endl;
};

void SettingDeclare()
{
    cout<<"(1) Declare a Specific Function From a List to be Solved " << endl;
    cout<<"(2) Change the No. of Significant Figures" << endl;
    cout<<"(3) Change No. Of Iterations to be used" << endl;
    cout<<"(4) Set the Root-Finding Method to be used" << endl;
    cout<<"(5) Set it so Intermediate Values would be shown?" << endl;
};


void End_Inter()
{
     cout << "*******************\n";
     cout << "| End of Interval |\n";
     cout << "*******************\n";
}

double RelativeDiff(double theoretical, double experimental) //Relative DIfference Checker
    {
        return fabs((experimental-theoretical)/theoretical);
    }

    // for the function sin(x)-e^(-0.1x); the derivative is 0.1*e^(-0.1x) + cos(x)
    // equation for Newton-Raphson is x1= x0 - f(x0)/f'(x0)
   void NewtonMethod(double (*func) (double), double (*dfunc) (double), double guess, float sigf, int iterate, int interm) //Implementing Newton Method
{
    double error  = (1*(pow(10,-sigf)));
    double previous, current;
    current = guess;
    for (int i = 0; i< iterate+1 ; i++)
    {
        previous = current; //Solving for the Newton means guess = guess-f(guess)/f'(guess)
        current = previous - (func(previous)/dfunc(previous));
        //previous - (sin(previous)- exp(-0.1*previous))/(0.1*exp(-0.1*previous) + cos(previous));
        if(  RelativeDiff(current, previous) < error)
        {
            cout<< "The Answer for Newton is: "<<setprecision(sigf) << current << " Found in a total of "<< i << " iterations" << endl;
            i = iterate;
        }
        if(  RelativeDiff(current, previous) > error && i == iterate-1)
        {
            cout<< "Newton-Raphson: No Answer Could be Found within the number of Iterations " << endl;
        }
        if(  RelativeDiff(current, previous) > error && interm == 1)
        {
            cout<< "The Intermediate Answer for Newton is: "<<setprecision(sigf) << current << " Found in "<< i << " iterations" << endl;
        }
        }
    }
    
    void SecantMethod(double (*func) (double), double guessLower, double guessHigher, float sigf, int iterate, int interm) //Implementing Secant Method
    { //Secant Method is solved by f(x)=x1-f(x1)*[(higher-lower)/f(x1)-f(x0)]
        double error  = (1*(pow(10,-sigf)));
        double previous, current, currentplus;
        previous = guessLower;
        current = guessHigher;
        for (int i=0; i< iterate; i++)
        {
            currentplus = current - 
            (func(current))* 
            (current - previous)/
            (func(current)-func(previous));
            previous = current;
            current = currentplus;
            if(  RelativeDiff(current, previous) < error)
        {
            cout<< "The Answer for Secant is: " <<setprecision(sigf)<< current << " Found in a total of "<< i << " iterations" << endl;
            i = iterate; 
        }
        if(  RelativeDiff(current, previous) > error && i == iterate-1)
        {
           cout<< "Secant Method: No Answer Could be Found within the number of Iterations " << endl; 
        }
        if(  RelativeDiff(current, previous) > error &&  interm == 1)
        {
            cout<< "The Answer for Secant is: " <<setprecision(sigf)<< current << " Found in "<< i << " iterations" << endl;
        }

    }
}
    
        void BisectionMethod(double (*func) (double), double guessLower, double guessHigher, float sigf, int iterate, int interm) // Implementing Bisection Method
    {
        double error  = (1*(pow(10,-sigf))); // sets the accuracy level wanted
        double left, right, midpoint, storeold, storemid, storeleft;
        left = guessLower;
        right = guessHigher;
        for (int i=0; i< iterate+1; i++)
        {
            midpoint = (left+right)/2.0;
            storemid = func(midpoint);
            storeleft= func(left);
            if(storemid*storeleft < 0.0)
            {
              if(RelativeDiff(midpoint,left) < error)
              {
                cout<< "The Answer for Bisection Method is: " <<setprecision(sigf) << midpoint << "Found in a total of "<< i << " iterations" << endl;
                i= iterate;
                }
                 if(RelativeDiff(midpoint,left) > error && i==iterate-1)
              {
                cout<< "Bisction Method : No Answer Could be Found within the number of Iterations " << endl; 
                }
                if(RelativeDiff(midpoint,left) < error &&  interm == 1)
              {
                cout<< "The Intermediate Answer for Bisection Method is: "<<setprecision(sigf) << midpoint << " Found in "<< i << " iterations" << endl;
                }
                right = midpoint;
                //storeold = midpoint;  
            }
            else
            {
              if(RelativeDiff(midpoint,right) < error)
              {
                cout<< "The Answer for Bisection Method is: "<<setprecision(sigf) << midpoint << " Found in a total of "<< i << " iterations" << endl;
                i= iterate;
                }
                if(RelativeDiff(midpoint,right) > error && i==iterate-1)
              {
                cout<< "Bisction Method : No Answer Could be Found within the number of Iterations " << endl; 
                }
                if(RelativeDiff(midpoint,right) > error && interm == 1)
              {
                cout<< "The Intermediate Answer for Bisection Method is: "<<setprecision(sigf) << midpoint << " Found in "<< i << " iterations" << endl;
                }
                left = midpoint;
                //storeold = midpoint;  
            }
        }
    }

    
    void FalsePosition(double (*func) (double),double guessLower, double guessHigher, float sigf, int iterate, int interm)
    { //=UpperBound-(UpperFunct*(LowerBound-UpperBound))/(LowerFunct-UpperFunct)
        double error  = (1*(pow(10,-sigf))); // sets the accuracy level wanted
        double previous, current, currentplus, storeprev, storecurrent, storemid,storeold;
        previous = guessLower;
        current = guessHigher;
        for (int i = 0; i < iterate+1; i++)
        {
            storeprev= func(previous);
            storecurrent= func(current);
            currentplus = current - (storecurrent*(previous-current))/(storeprev-storecurrent);
            storemid = func(currentplus);
            if (storemid < 0)
            {
              if (RelativeDiff(currentplus, storeold) < error)
              {
                    cout<< "The Answer for False Position Method is: "<<setprecision(sigf) << currentplus << " Found in a total of "<< i << " iterations" << endl;
                    i= iterate;
                }
                if (RelativeDiff(currentplus, storeold) > error && i == iterate-1)
              {
                   cout<< " False Position: No Answer Could be Found within the number of Iterations " << endl; 
                }
                 if (RelativeDiff(currentplus, storeold) < error  && interm == 1)
              {
                    cout<< "The Intermediate Answer for False Position Method is: " << currentplus << " Found in "<< i << " iterations" << endl;
                }
              previous = currentplus;
              storeold = currentplus;
            }
            if (storemid > 0)
            {
              if (RelativeDiff(currentplus, storeold) < error)
              {
                    cout<< "The Answer for False Position Method is: " << currentplus << " Found in a total of "<< i << " iterations" << endl;
                    i= iterate;
                }
            if (RelativeDiff(currentplus, storeold) > error && i == iterate-1)
              {
                    cout<< " False Position: No Answer Could be Found within the number of Iterations " << endl; 
                }
                 if (RelativeDiff(currentplus, storeold) < error  && interm == 1)
              {
                    cout<< "The Intermediate Answer for False Position Method is: " << currentplus << " Found in "<< i << " iterations" << endl;
                }   
              current = currentplus;
              storeold = currentplus;
            }
        }
    }
void Graph(double (*func) (double), double LowerBound, double UpperBound, double Iteration) //Graphs the function
{
    double steps = (UpperBound - LowerBound)/Iteration;
    cout << "Points of the graph" << endl;
    for ( LowerBound; LowerBound <= UpperBound; LowerBound = LowerBound+steps)
    cout << "(" << LowerBound << "," << func(LowerBound) << ")" << endl;
    End_Inter();
};
        

    
    

    
//sin(x) - exp(-0.1*x) 
